import { 
  MeshBasicMaterial, PerspectiveCamera, Scene, Color, PlaneGeometry, Mesh, AmbientLight, GridHelper,
  DirectionalLight, WebGLRenderer, BoxGeometry} from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import {
  CSS2DRenderer,
  CSS2DObject,
} from "three/examples/jsm/renderers/CSS2DRenderer.js";

class City3D {
  constructor(opt) {
    let container = opt.container;
    if (typeof container === "string") {
      this.container = document.querySelector(container);
    } else {
      this.container = container;
    }
    this.width = this.container.clientWidth;
    this.height = this.container.clientHeight;

    this.materialNormal = new MeshBasicMaterial({
      color: 0x8edafe,
    });

    this.materialWarning = new MeshBasicMaterial({
      color: 0xfcff8e,
    });

    this.materialAlert = new MeshBasicMaterial({
      color: 0xff0000,
    });

    // 
    this.objects = [];
    this.groundSize = 1000;
  }
  init() {
    this.initCamera();   // 初始化摄像机
    this.initScene();    // 初始化场景
    // 增加坐标轴
    if (this.gridHelper) {
      this.addGridHelper();
    }

    // 增加地板
    this.addPlane();
    // 增加灯光
    this.addLights();
    // 初始化渲染器
    this.initRenderer();
    
    this.addControls();
  }

  /**
   * 初始化摄像机
   */
  initCamera() {
    let camera = new PerspectiveCamera(
      45,
      this.width / this.height,
      1,
      10000
    );
    camera.position.set(0, 1000, 1200);
    camera.lookAt(0, 0, 0);
    this.camera = camera;
  }

  /**
   * 初始化场景
   */
  initScene() {
    let scene = new Scene();
    let backgroundColor = 0xf0f0f0;
    // let backgroundColor = 0x000000;
    scene.background = new Color(backgroundColor);
    this.scene = scene;
  }

  /**
   * 增加地板
   */
  addPlane() {
    const geometry = new PlaneGeometry(
        this.groundSize + 100,
        this.groundSize + 100
      );
      geometry.rotateX(-Math.PI / 2);
  
    let plane = new Mesh(
        geometry,
        new MeshBasicMaterial({ visible: true })
      );
      this.scene.add(plane);
  
      this.objects.push(plane);
  }

  // 增加坐标轴
  addGridHelper() {
    const gridHelper = new GridHelper(groundSize, 40);
    scene.add(gridHelper);
  }

  /**
   * 增加灯光
   */
  addLights() {
    // lights
    const ambientLight = new AmbientLight(0x606060, 3);
    this.scene.add(ambientLight);

    const directionalLight = new DirectionalLight(0xffffff, 3);
    directionalLight.position.set(1, 0.75, 0.5).normalize();
    this.scene.add(directionalLight);
  }

  initRenderer() {
    let renderer = new WebGLRenderer({ antialias: true });
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.setSize(this.width, this.height);
    this.container.appendChild(renderer.domElement);
    this.renderer = renderer;

    let labelRenderer = new CSS2DRenderer();
    labelRenderer.setSize(this.width, this.height);
    labelRenderer.domElement.style.position = "absolute";
    labelRenderer.domElement.style.top = "0px";
    this.container.appendChild(labelRenderer.domElement);
    this.labelRenderer = labelRenderer;
  }

  addControls() {
    // controls
    const controls = new OrbitControls(this.camera, this.labelRenderer.domElement);
    controls.addEventListener("change", ()=>{
        this.render();
    });
    controls.enablePan = false;
  }

  setBuildings(buildings) {
    this.buildings = buildings;
    this.addMeshByBuildings();
  }

  /**
   * 获取建筑
   */
  addMeshByBuildings() {
    const groundSize = this.groundSize;
    this.buildings.forEach((b) => {
      // roll-over helpers
      let buildHeight = 25;

      const buildBlock = new BoxGeometry(b.width, buildHeight, b.height);
      let rollOverMesh;
      if (b.level === 3) {
        rollOverMesh = new Mesh(buildBlock, this.materialAlert);
      } else if (b.level === 2) {
        rollOverMesh = new Mesh(buildBlock, this.materialWarning);
      } else {
        rollOverMesh = new Mesh(buildBlock, this.materialNormal);
      }

      rollOverMesh.position.set(
        -groundSize / 2 + b.left + b.width / 2,
        buildHeight / 2,
        -groundSize / 2 + b.top + b.height / 2
      );
      this.scene.add(rollOverMesh);

      const earthDiv = document.createElement("div");

      earthDiv.innerHTML = "<div class=label>" + b.name + "</div>";
      earthDiv.style.backgroundColor = "transparent";

      const earthLabel = new CSS2DObject(earthDiv);
      earthLabel.position.set(0, 0, 0);
      earthLabel.center.set(0, 0);
      rollOverMesh.add(earthLabel);
    });
  }

  resize() {
    let container = this.container;
    this.width = container.clientWidth;
    this.height = container.clientHeight;
    this.camera.aspect = this.width / this.height;
    this.camera.updateProjectionMatrix();
    this.renderer.setSize(this.width, this.height);
    this.labelRenderer.setSize(this.width, this.height);
  }

  render() {
    this.renderer.render(this.scene, this.camera);
    this.labelRenderer.render(this.scene, this.camera);
  }
}

export default City3D;
